#include "stdafx.h"
#include "MarchingCubeTable.h"
#include <iostream>

MarchingCubeTable* MarchingCubeTable::mct = 0;

//Initialize the mapTable
int MarchingCubeTable::mapTable[15][12] = {
{0,0,0,0,0,0,0,0,0,0,0,0},
{192,144,132,0,0,0,0,0,0,0,0,0},
{144,132,72,72,144,96,0,0,0,0,0,0},
{192,144,132,72,12,9,0,0,0,0,0,0},
{192,144,132,33,9,3,0,0,0,0,0,0},
 {192,144,72,144,72,18,72,18,33,0,0,0},
{144,132,72,72,144,96,33,9,3,0,0,0},
{192,96,72,132,12,6,33,9,3,0,0,0},
{132,72,33,132,33,18,0,0,0,0,0,0},
{132,6,3,132,3,192,192,3,33,33,192,96},
{192,144,12,144,12,6,96,48,9,48,9,3},
{192,132,18,192,18,9,18,9,3,192,96,9},
{132,12,6,192,144,72,144,72,18,72,18,33},
{192,144,132,72,12,9,18,6,3,96,48,33},
{192,144,6,192,6,33,192,33,72,6,33,3}
};

int MarchingCubeTable::rotate[48][8] = {
	{2,3,0,1,6,7,4,5},
	{2,1,0,3,4,7,6,5},
	{6,3,0,5,2,7,4,1},
	{1,2,3,0,7,4,5,6},
	{3,2,1,0,7,6,5,4},
	{5,6,3,0,7,4,1,2},
	{4,5,0,1,6,7,2,3},
	{4,1,0,5,2,7,6,3},
	{6,5,0,3,4,7,2,1},
	{1,4,5,0,7,2,3,6},
	{5,4,1,0,7,6,3,2},
	{3,6,5,0,7,2,1,4},

	{0,1,4,5,2,3,6,7},
	{0,1,2,3,4,5,6,7},
	{0,5,6,3,4,1,2,7},
	{0,3,6,5,2,1,4,7},
	{0,5,4,1,6,3,2,7},
	{0,3,2,1,6,5,4,7},
	{1,0,5,4,3,2,7,6},
	{1,0,3,2,5,4,7,6},
	{5,0,1,4,3,6,7,2},
	{3,0,1,2,5,6,7,4},
	{3,0,5,6,1,2,7,4},
	{5,0,3,6,1,4,7,2},

	{5,4,7,6,1,0,3,2},
	{3,2,7,6,1,0,5,4},
	{1,2,7,4,3,0,5,6},
	{1,4,7,2,5,0,3,6},
	{5,6,7,4,3,0,1,2},
	{3,6,7,2,5,0,1,4},
	{4,5,6,7,0,1,2,3},
	{2,3,6,7,0,1,4,5},
	{6,5,4,7,0,3,2,1},
	{6,3,2,7,0,5,4,1},
	{2,1,4,7,0,3,6,5},
	{4,1,2,7,0,5,6,3},

	{4,7,6,5,2,1,0,3},
	{2,7,6,3,4,1,0,5},
	{2,7,4,1,6,3,0,5},
	{4,7,2,1,6,5,0,3},
	{6,7,4,5,2,3,0,1},
	{6,7,2,3,4,5,0,1},
	{7,6,5,4,3,2,1,0},
	{7,6,3,2,5,4,1,0},
	{7,4,5,6,1,2,3,0},
	{7,2,3,6,1,4,5,0},
	{7,2,1,4,3,6,5,0},
	{7,4,1,2,5,6,3,0}
};

MarchingCubeTable::MarchingCubeTable(void)
{
	initTMap();
	initRotate();
}

MarchingCubeTable::~MarchingCubeTable(void)
{
}

void MarchingCubeTable::initTMap(void)
{
	//Set the map of marching cube table
	/*Vertices of the cube are indexed as follows:
	
	      6-----7
	    / |      /|         y 
	  /   |    /  |         |
	 5---+--4   |         |
	 |    3--+---2        +-----x
	 |   /    |   /        /
	 | /      | /        /
	 0------1        z
	
	
	*/

	//case:0
	//key= 1111 1111B
	int key = 255;
	//int value[12]={0,0,0,0,0,0,0,0,0,0,0,0};
	tmap[key] = mapTable[0];
	tmap.insert(make_pair(key, mapTable[0]));

	//case:1
	//key= 1000 0000B
	//value = 192(11000000),144(10010000),132(10000100)
	key = 128;
	//int value1[12] = {192,144,132,0,0,0,0,0,0,0,0,0};
	tmap[key] = mapTable[1];
	tmap.insert(make_pair(key, mapTable[1]));

	//case:2
	//key= 1100 0000B
	//value = 144(10010000),132(10000100),72(01001000),72(01001000),144(10010000),96(01100000)
	key = 192;
	//int value2[12] = {144,132,72,72,144,96,0,0,0,0,0,0};
	tmap[key] = mapTable[2];
	tmap.insert(make_pair(key, mapTable[2]));

	//case:3
	//key= 1000 1000B
	//value = 192(11000000),144(10010000),132(10000100),72(01001000),12(00001100),9(00001001)
	key = 136;
	// int value3[12] = {192,144,132,72,12,9,0,0,0,0,0,0};
	tmap[key] = mapTable[3];
	tmap.insert(make_pair(key, mapTable[3]));

	//case:4
	//key= 1000 0001B
	//value = 192(11000000),144(10010000),132(10000100),33(00100001),9(00001001),3(00000011)
	key = 129;
	tmap[key] = mapTable[4];
	tmap.insert(make_pair(key, mapTable[4]));

	//case:5
	//key= 1000 1111B
	//value = 192(11000000),144(10010000),72(01001000),144(10010000),72(01001000),18(00010010),72(01001000),18(00010010),33(00100001)
	key = 143;
	tmap[key] = mapTable[5];
	tmap.insert(make_pair(key, mapTable[5]));

	//case:6
	//key= 1100 0001B
	//value = 144(10010000),132(10000100),72(01001000),72(01001000),144(10010000),96(01100000),33(00100001),9(00001001),3(00000011)
	key = 193;
	tmap[key] = mapTable[6];
	tmap.insert(make_pair(key, mapTable[6]));

	//case:7
	//key= 1011 1010B
	//value = 192(11000000),96(01100000),72(01001000),132(10000100),12(00001100),6(00000110),33(00100001),9(00001001),3(00000011)
	key = 186;
	tmap[key] = mapTable[7];
	tmap.insert(make_pair(key, mapTable[7]));

	//case:8
	//key= 1111 0000B
	//value = 132(10000100),72(01001000),33(00100001),132(10000100),33(00100001),18(00010010)
	key = 240;
	tmap[key] = mapTable[8];
	tmap.insert(make_pair(key, mapTable[8]));

	//case:9
	//key= 1011 0010B
	//value = 132(10000100),6(00000110),3(00000011),132(10000100),3(00000011),192(11000000),192(11000000),3(00000011),33(00100001),33(00100001),192(11000000),96(01100000)
	key = 178;
	tmap[key] = mapTable[9];
	tmap.insert(make_pair(key, mapTable[9]));

	//case:10
	//key= 1010 0101B
	//value = 192(11000000),144(10010000),12(00001100),144(10010000),12(00001100),6(00000110),96(01100000),48(00110000),9(00001001),48(00110000),9(00001001),3(00000011)
	key = 165;
	tmap[key] = mapTable[10];
	tmap.insert(make_pair(key, mapTable[10]));

	//case:11
	//key= 1011 0001B
	//value = 192(11000000),132(10000100),18(00010010),192(11000000),18(00010010),9(00001001),18(00010010),9(00001001),3(00000011),192(11000000),96(01100000),9(00001001)
	key = 177;
	tmap[key] = mapTable[11];
	tmap.insert(make_pair(key, mapTable[11]));

	//case:12
	//key= 1000 1011B
	//value = 132(10000100),12(00001100),6(00000110),192(11000000),144(10010000),72(01001000),144(10010000),72(01001000),18(00010010),72(01001000),18(00010010),33(00100001)
	key = 139;
	tmap[key] = mapTable[12];
	tmap.insert(make_pair(key, mapTable[12]));;

	//case:13
	//key= 1010 1010B
	//value = 192(11000000),144(10010000),132(10000100),72(01001000),12(00001100),9(00001001),18(00010010),6(00000110),3(00000011),96(01100000),48(00110000),33(00100001)
	key = 170;
	tmap[key] = mapTable[13];
	tmap.insert(make_pair(key, mapTable[13]));

	//case:14
	//key= 1000 1101B
	//value = 192(11000000),144(10010000),6(00000110),192(11000000),6(00000110),33(00100001),192(11000000),33(00100001),72(01001000),6(00000110),33(00100001),3(00000011)
	key = 141;
	tmap[key] = mapTable[14];
	tmap.insert(make_pair(key, mapTable[14]));

}

void MarchingCubeTable::initRotate(void)
{
	//Set the array of rotation
	/*Vertices of the cube are indexed as follows:
	
	      6-----7
	    / |      /|         y 
	  /   |    /  |         |
	 5---+--4   |         |
	 |    3--+---2        +-----x
	 |   /    |   /        /
	 | /      | /        /
	 0------1        z
	
	
	rotate = { {3, 0, 1, 2, 5, 6, 7, 4},
				   {2, 3, 0, 1, 6, 7, 4, 5},
	            {1, 2, 3, 0, 7, 4, 5, 6},
	            {6, 5, 4, 7, 0, 3, 2, 1},
	            {5, 4, 7, 6, 1, 0, 3, 2},
	            {4, 7, 6, 5, 2, 1, 0, 3},
	            {7, 6, 5, 4, 3, 2, 1, 0} };*/
	//rotate[0]: rotate 90 degree, look from 1
	/*rotate[0][0] = 3;
	rotate[0][1] = 0;
	rotate[0][2] = 1;
	rotate[0][3] = 2;
	rotate[0][4] = 5;
	rotate[0][5] = 6;
	rotate[0][6] = 7;
	rotate[0][7] = 4;

	//rotate[1]: rotate 180 degree, look from 2
	rotate[1][0] = 2;
	rotate[1][1] = 3;
	rotate[1][2] = 0;
	rotate[1][3] = 1;
	rotate[1][4] = 6;
	rotate[1][5] = 7;
	rotate[1][6] = 4;
	rotate[1][7] = 5;	

	//rotate[2]: rotate 270 degree, look from 3
	rotate[2][0] = 1;
	rotate[2][1] = 2;
	rotate[2][2] = 3;
	rotate[2][3] = 0;
	rotate[2][4] = 7;
	rotate[2][5] = 4;
	rotate[2][6] = 5;
	rotate[2][7] = 6;	

	//rotate[3]: look from 4
	rotate[3][0] = 6;
	rotate[3][1] = 5;
	rotate[3][2] = 4;
	rotate[3][3] = 7;
	rotate[3][4] = 0;
	rotate[3][5] = 3;
	rotate[3][6] = 2;
	rotate[3][7] = 1;	

	//rotate[4]: look from 5
	rotate[4][0] = 5;
	rotate[4][1] = 4;
	rotate[4][2] = 7;
	rotate[4][3] = 6;
	rotate[4][4] = 1;
	rotate[4][5] = 0;
	rotate[4][6] = 3;
	rotate[4][7] = 2;	

	//rotate[5]: look from 6
	rotate[5][0] = 4;
	rotate[5][1] = 7;
	rotate[5][2] = 6;
	rotate[5][3] = 5;
	rotate[5][4] = 2;
	rotate[5][5] = 1;
	rotate[5][6] = 0;
	rotate[5][7] = 3;

	//rotate[6]: look from 7
	rotate[6][0] = 7;
	rotate[6][1] = 6;
	rotate[6][2] = 5;
	rotate[6][3] = 4;
	rotate[6][4] = 3;
	rotate[6][5] = 2;
	rotate[6][6] = 1;
	rotate[6][7] = 0;*/
	//case0: 
	/*rotate[0][0] = 0;
	rotate[0][1] = 1;
	rotate[0][2] = 2;
	rotate[0][3] = 3;
	rotate[0][4] = 4;
	rotate[0][5] = 5;
	rotate[0][6] = 6;
	rotate[0][7] = 7;*/
}

MarchingCubeTable* MarchingCubeTable::getInstance()
{
	if(mct == 0)
	{
		mct = new MarchingCubeTable();
	}
	return mct;
}

bitset<8>* MarchingCubeTable::getTriangles(bitset<8> input)
{
	//Match the current input bitset with the marching cube table
	//if there are not any match cases, rotate the input bitset with 
	//    the rotate table, and match again
	//There must be one case matched
	bool t;
	int t_key;
	int *t_value;
	bitset<8> t_input;
	
	//Step1: Flip the bitset if the first element of the bitset is 0
	t = input.test(7);
	if(!t)
	{
		input.flip();
	}
	//Step2: Try to match the current bitset with the marching cube table
	t_key = (int)input.to_ulong();
	//cout<<"key is "<<t_key<<endl;
	if(tmap.find(t_key) != tmap.end())
	{
		//Find the matching cases and return the triangles sequence
		t_value = tmap[t_key];
		for(int i=0; i<12; i++)
		{
			bitset<8> temp(t_value[i]);
			//cout<<"temp is "<<temp<<endl;
			triangles[i] = temp;
		}
	//////////////////////////////test//////////////////////////
		for(int i=0; i<12; i++)
		{
			//cout<<"triangles bitset is: "<<triangles[i]<<endl;
		}
		return triangles;
	}

	for(int i=0; i<48; i++)
	{
		//rotate at most 7 times to match the marching cube table
		//Step3: Rotate the input bitset if there are not any match cases
		t_input = rot(input, rotate[i]);
		//cout<<"t_input is "<<t_input<<endl;
		//Step1: Flip the bitset if the first element of the bitset is 0
		t = t_input.test(7);
		if(!t)
		{
			t_input.flip();
		}
		//Step2: Try to match the current bitset with the marching cube table
		t_key = (int)t_input.to_ulong();
		if(tmap.find(t_key) != tmap.end())
		{
			//Find the matching cases and return the triangles sequence
			//Must rotate back the sequence
			t_value = tmap[t_key];
			for(int j=0; j<12; j++)
			{
				bitset<8> temp(t_value[j]);
				//cout<<"t_value is"<<t_value[j]<<endl;
						//cout<<"temp is "<<temp<<endl;
				if(t_value[j] != 0)
				{
					//Rotate the triangles sequence back
					temp = revert(temp, rotate[i]);
				}
							//cout<<"temp is "<<temp<<endl;
				triangles[j] = temp;
			}
			break;
		}		
	}
	//////////////////////////////test//////////////////////////
	for(int i=0; i<12; i++)
	{
		//cout<<"triangles bitset is: "<<triangles[i]<<endl;
	}
	return triangles;
}

bitset<8> MarchingCubeTable::rot(bitset<8> input, int* rotate_array)
{
	bitset<8> result;
	int index;
	for(int i=0; i<8; i++)
	{
		index = rotate_array[i];
		if(input.test(7-i))
		{
			result.set(7-index);
		}
	}
	return result;
}

bitset<8> MarchingCubeTable::revert(bitset<8> input, int* rotate_array)
{
	bitset<8> result;
	int index;
	for(int i=0; i<8; i++)
	{
		index = rotate_array[i];
		if(input.test(7-index))
		{
			result.set(7-i);
		}
	}
	return result;
}
